package org.tulkas.selector.pattern;

import org.tulkas.selector.Filter;
import org.w3c.dom.Element;

/**
 * @author <a href="mailto:tulkas.web@gmail.com">Tulkas</a>
 *
 */
public abstract class Attr implements Filter {
	private final String name;
	private final String value;

	protected Attr(String name, String value) {
		if (name == null) {
			throw new NullPointerException("Attribute name can't be null!");
		}
		this.name = name;
		this.value = value;
	}

	@Override
	public boolean matches(Element element) {
		String valueActual = element.getAttribute(name);
		if (valueActual == null) {
			valueActual = element.getAttribute(name.toLowerCase());
		}
		return matchAttr(value, valueActual);
	}

	public String getName() {
		return name;
	}

	public String getValue() {
		return value;
	}

	protected abstract boolean matchAttr(String valueExpect, String valueActual);

	protected abstract String getOperatorName();

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(name).append(" ").append(getOperatorName());
		if (value != null) {
			sb.append(" '").append(value).append("'");
		}

		return sb.toString();
	}

	public static class With extends Attr {
		public With(String name, String value) {
			super(name, value);
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR + 30;
		}

		@Override
		protected String getOperatorName() {
			return "exists";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			return valueActual != null;
		}
	}

	public static class Equals extends Attr {
		public Equals(String name, String value) {
			super(name, value);
			if (value == null) {
				throw new NullPointerException("Attribute value of '" + name
						+ "' can't be null!");
			}
		}

		@Override
		protected String getOperatorName() {
			return "=";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			return valueExpect.equals(valueActual);
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR;
		}
	}

	public static class Contains extends Attr {
		public Contains(String name, String value) {
			super(name, value);
			if (value == null) {
				throw new NullPointerException("Attribute value of '" + name
						+ "' can't be null!");
			}
		}

		@Override
		protected String getOperatorName() {
			return "contains";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			String[] strs = valueActual.split("\\s+");
			for (String str : strs) {
				if (valueExpect.equals(str)) {
					return true;
				}
			}
			return false;
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR + 20;
		}
	}

	public static class StartsWith extends Attr {
		public StartsWith(String name, String value) {
			super(name, value);
			if (value == null) {
				throw new NullPointerException("Attribute value of '" + name
						+ "' can't be null!");
			}
		}

		@Override
		protected String getOperatorName() {
			return "starts with";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			return valueActual != null && valueActual.startsWith(valueExpect);
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR + 10;
		}
	}

	public static class EndsWith extends Attr {
		public EndsWith(String name, String value) {
			super(name, value);
			if (value == null) {
				throw new NullPointerException("Attribute value of '" + name
						+ "' can't be null!");
			}
		}

		@Override
		protected String getOperatorName() {
			return "ends with";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			return valueActual != null && valueActual.endsWith(valueExpect);
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR + 10;
		}
	}

	public static class SubString extends Attr {
		public SubString(String name, String value) {
			super(name, value);
			if (value == null) {
				throw new NullPointerException("Attribute value of '" + name
						+ "' can't be null!");
			}
		}

		@Override
		protected String getOperatorName() {
			return "has substring ";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			return valueActual != null
					&& (valueActual.indexOf(valueExpect) > 0);
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR + 10;
		}
	}

	public static class HyphenBegin extends Attr {
		public HyphenBegin(String name, String value) {
			super(name, value);
			if (value == null) {
				throw new NullPointerException("Attribute value of '" + name
						+ "' can't be null!");
			}
		}

		@Override
		protected String getOperatorName() {
			return "hyphenated with";
		}

		@Override
		protected boolean matchAttr(String valueExpect, String valueActual) {
			String[] strs = valueActual.split("-");
			for (String str : strs) {
				if (valueExpect.equals(str)) {
					return true;
				}
			}
			return false;
		}

		@Override
		public int getPriority() {
			return PRIORITY_ATTR + 10;
		}
	}
}
